package cn.qu.v1.platform.plugin;

import cn.qu.v1.platform.plugin.loader.PluginLoader;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.io.File;
import java.io.IOException;
import java.util.Optional;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * Created by zh on 2017/1/7.
 */
public class Plugin {

    private Meta meta;
    private PluginLoader pluginLoader;

    private ClassLoader parentClassLoader;

    public void setParentClassLoader(ClassLoader parentClassLoader) {
        this.parentClassLoader = parentClassLoader;
    }

    public static Plugin create(File pluginFile) {
        return create(pluginFile, null);
    }

    public static Plugin create(File pluginFile, ClassLoader parentClassLoader) {

        try (JarFile jarFile = new JarFile(pluginFile, true)) {

            Manifest manifest = jarFile.getManifest();
            Attributes mainAttrs = manifest.getMainAttributes();

            Plugin plugin = new Plugin(parentClassLoader);
            Meta meta = new Meta();
            meta.enterClass = StringUtils.trimToEmpty(mainAttrs.getValue("Enter-Class"));
            meta.pluginName = StringUtils.trimToEmpty(mainAttrs.getValue("Plugin-Name"));
            meta.versionCode = NumberUtils.toInt(mainAttrs.getValue("Version-Code"));
            meta.versionName = StringUtils.trimToEmpty(mainAttrs.getValue("Version-Name"));
            String dependsOn = StringUtils.trimToEmpty(mainAttrs.getValue("Depends-On"));
            meta.dependsOn = dependsOn.split(",");

            meta.path = pluginFile.getCanonicalPath();
            plugin.meta = meta;
            return plugin;
        } catch (IOException e) {
            return null;
        }
    }

    public Plugin loadPlugin() {
        this.pluginLoader = PluginLoader.create(new String[]{this.getMeta().getPath()}, parentClassLoader);
        return this;
    }

    public ClassLoader getClassLoader() {
        return pluginLoader;
    }

    public Optional<Class> loadClass(String className) {
        Optional<Class> optional = Optional.empty();
        if (this.pluginLoader != null) {
            try {
                Class clazz = this.pluginLoader.loadClass(className);
                optional = Optional.ofNullable(clazz);
            } catch (ClassNotFoundException e) {
            }
        }
        return optional;
    }

    public Meta getMeta() {
        return meta;
    }

    private Plugin() {
    }

    private Plugin(ClassLoader parentClassLoader) {
        this.parentClassLoader = parentClassLoader;
    }

    public static class Meta {
        private String path;
        private String pluginName;
        private int versionCode;
        private String versionName;
        private String[] dependsOn;
        private String enterClass;

        public String getPluginName() {
            return pluginName;
        }

        public int getVersionCode() {
            return versionCode;
        }

        public String getVersionName() {
            return versionName;
        }

        public String getEnterClass() {
            return enterClass;
        }

        public String getPath() {
            return path;
        }

        public String[] getDependsOn() {
            return dependsOn;
        }
    }
}
